{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**问题：**\n",
    "假设你正在为一个电影推荐系统设计一个简单的KNN算法。我们有以下一些用户的电影评分数据，数据由两个特征组成：用户对电影A和电影B的评分，分别在1-5之间。用户的标签（电影类型偏好）是动作片（标签0）或者是喜剧片（标签1）。我们有一个新用户，他给电影A评分为3，电影B评分为4。请问这个用户可能偏好哪种类型的电影？\n",
    "\n",
    "**数据：**\n",
    "\n",
    "| 用户   | 电影A评分 | 电影B评分 | 偏好类型 |\n",
    "| ------ | --------- | --------- | -------- |\n",
    "| 用户1  | 5         | 1         | 动作片   |\n",
    "| 用户2  | 4         | 2         | 动作片   |\n",
    "| 用户3  | 2         | 5         | 喜剧片   |\n",
    "| 用户4  | 1         | 4         | 喜剧片   |\n",
    "| 用户5  | 3         | 2         | 动作片   |\n",
    "| 用户6  | 2         | 5         | 喜剧片   |\n",
    "\n",
    "你需要做以下步骤：\n",
    "1. 构造数据\n",
    "2. 创建KNN模型\n",
    "3. 使用数据训练模型\n",
    "4. 预测新用户的喜好"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 0. 引入核心包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.neighbors import KNeighborsClassifier"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. X, y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = np.array([[5,1],[4,2],[2,5],[1,4],[3,2],[2,5]])\n",
    "\n",
    "y = np.array([0,0,1,1,0,1])# 0表示动作片，1表示喜剧片"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 创建 KNN 模型\n",
    "k = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "knn = KNeighborsClassifier(n_neighbors=1)\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: black;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-1 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-1 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: block;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-1 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-1 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 1ex;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-1 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>KNeighborsClassifier(n_neighbors=1)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;&nbsp;KNeighborsClassifier<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.neighbors.KNeighborsClassifier.html\">?<span>Documentation for KNeighborsClassifier</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></label><div class=\"sk-toggleable__content fitted\"><pre>KNeighborsClassifier(n_neighbors=1)</pre></div> </div></div></div></div>"
      ],
      "text/plain": [
       "KNeighborsClassifier(n_neighbors=1)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# TODO\n",
    "knn.fit(X,y)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. 用模型推理(预测)用户的喜好"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_user = np.array([[3, 4]])\n",
    "prediction = knn.predict(new_user)#TODO\n",
    "new_user_class=prediction[0]\n",
    "labels=['动作片','喜剧片']"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. 数据可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.title(\"User Movie Preference\", size=15) \n",
    "plt.xlabel(\"Movie A rating\")\n",
    "plt.ylabel(\"Movie B rating\")\n",
    "plt.grid()\n",
    "from sklearn.neighbors import NearestNeighbors \n",
    "\n",
    "# 绘制原始样本点，要求不同的影片喜好类别用不同的颜色标记\n",
    "# 提示: 用scatter散点图绘制，用它的参数c实现不同的类别用不同的颜色标记\n",
    "#TODO\n",
    "scatter = plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', s=50) \n",
    "# 绘制新数据点，用红色x标记，大小为8\n",
    "# 提示：用plt.plot()绘制，用它的参数marker实现不同的标记符号\n",
    "#TODO\n",
    "new_user = np.array([[5, 2]])   \n",
    "plt.plot(new_user[:, 0], new_user[:, 1], 'rx', markersize=8)  # 用红色x标记新数据点  \n",
    " \n",
    "# 新数据最近邻索引为第一个最近邻的索引\n",
    "nbrs = NearestNeighbors(n_neighbors=1).fit(X)\n",
    "dist, idx = nbrs.kneighbors(new_user)\n",
    "nearest = X[idx][0]\n",
    "#TODO\n",
    "nearest = X[idx][0] #TODO # 获取最近邻点的坐标，这是一个列表，第一个元素是x坐标，第二个元素是y坐标\n",
    "\n",
    "# 用红线标记新数据点与最近邻点的连接线\n",
    "# 提示：用plt.plot()绘制，用 r-- 实现红色虚线\n",
    "#TODO\n",
    "plt.plot([new_user[0, 0], nearest[0,0]], [new_user[0, 1], nearest[0,1]], 'r--') \n",
    "# 为每个点添加坐标文本  \n",
    "for x, y in zip(X[:, 0], X[:, 1]):\n",
    "    plt.text(x, y+0.1, f'({x}, {y})') \n",
    "\n",
    "# 为新数据点添加坐标文本\n",
    "plt.text(new_user[0,0], new_user[0,1]+0.1, f'({new_user[0,0]}, {new_user[0,1]})')\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
